package com.tionsy.springbootcomponents.common.login.aspect;

import com.tionsy.springbootcomponents.common.login.bean.ContextLog;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;
import java.util.UUID;

/**
 * <p></p>
 * <p>
 * <PRE>
 * <BR>    修改记录
 * <BR>-----------------------------------------------
 * <BR>    修改日期         修改人          修改内容
 * </PRE>
 *
 * @author tiany
 * @version 1.0
 * @date Created in 2021年02月07日 16:11
 * @since 1.0
 */
@Slf4j
@Aspect
@Component
public class LogAspect {

    private static String APP_NAME = "";

    @Autowired
    private Environment environment;

    @PostConstruct
    public void init(){
        String env = environment.getProperty("spring.application.name");
        APP_NAME = env == null ? "ApplicationLogAOP":env;
    }

    /**
     * 切入点
     */
    @Pointcut("execution(public * com.tionsy.springbootcomponents.controller..*.*(..))")
    public void controllerPointcut(){}

    /**
     * 设置切入点上线文参数
     */
    @Before("controllerPointcut()")
    public void beforeControllerLog(JoinPoint joinPoint){
        ContextLog.set(ContextLog.builder()
                .millisecond(System.currentTimeMillis())
                .traceId(UUID.randomUUID().toString())
                .build());
    }

    /**
     * 正常返回输出
     *
     */
    @AfterReturning(returning = "returnObj",pointcut = "controllerPointcut()")
    public void afterReturning(JoinPoint joinPoint,Object returnObj){
        ContextLog contextLog = ContextLog.get();
        long cost = System.currentTimeMillis() - contextLog.getMillisecond();
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest();

        String requestURI = request.getRequestURI();
        String addr = request.getRemoteAddr();
        String args = Arrays.toString(joinPoint.getArgs());
        String pkg = joinPoint.getSignature().getDeclaringTypeName();
        String methodName = pkg + "." + joinPoint.getSignature().getName();

        log.info("[ApplicationLog:{}] traceId:{}, reqAddr:{}, url:{}, methodName:{}, args:{}, returnVal:{}, cost:{} ms",
                APP_NAME,contextLog.getTraceId(),addr,requestURI,methodName,args,returnObj,cost);

        this.clean();
    }


    /**
     * 返回异常日志处理
     */
    @AfterThrowing(pointcut = "controllerPointcut()",throwing = "ex")
    public void afterThrowing(JoinPoint joinPoint , Exception ex){
        ContextLog contextLog = ContextLog.get();
        long cost = System.currentTimeMillis() - contextLog.getMillisecond();
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest();

        String requestURI = request.getRequestURI();
        String addr = request.getRemoteAddr();
        String args = Arrays.toString(joinPoint.getArgs());
        String pkg = joinPoint.getSignature().getDeclaringTypeName();
        String methodName = pkg + "." + joinPoint.getSignature().getName();

        log.info("[ApplicationLog:{}] traceId:{}, reqAddr:{}, url:{}, methodName:{}, args:{}, cost:{} ms",
                APP_NAME,contextLog.getTraceId(),addr,requestURI,methodName,args,cost,ex);

        this.clean();
    }

    /**
     * 清理上下文
     */
    private void clean(){
        ContextLog.clear();
    }
}



